package com.example.demo.util;

import cn.hutool.core.bean.BeanUtil;
import java.util.*;


/**
 * @description：树相关操作的工具函数.
 * @author：lw
 * @create_time：2024/1/17
 **/
public class TreeUtil {

    private void deepFindChildren(List<Map<String,Object>> list, Map<String,Object> targetNode , String idKey, String pIdKey){
        List<Map<String,Object>> children=new ArrayList<>();
        for(Map<String,Object> n:list){
            if(targetNode.get(idKey).equals(n.get(pIdKey))) children.add(n);
        }
        targetNode.put("children",children);
        list.remove(targetNode);
        for(Map<String,Object> n:children){
            deepFindChildren(list,n,idKey,pIdKey);
        }
    }

    private List<Map<String,Object>> sort(List<Map<String,Object>> list, String sortKey,boolean ASC){
        List <Map<String,Object>> res=new ArrayList<>();
        List<Map<String,Object>> list_sort=new ArrayList<>();
        List<Map<String,Object>> list_leave=new ArrayList<>();
        list.forEach(v->{
            Integer sort=(Integer)v.get(sortKey);
            if(sort!=null) list_sort.add(v);
            else list_leave.add(v);
        });
        list_sort.sort((pre,next)->{
            Integer preSort=(Integer)pre.get(sortKey);
            Integer nextSort=(Integer) next.get(sortKey);
            if(ASC) return preSort-nextSort;
            else return nextSort-preSort;
        });
        list_leave.sort((pre,next)->{
            Date preDate=(Date)pre.get("createTime");
            Date nextDate=(Date)next.get("createTime");
            if(ASC) {
                if(preDate.getTime() > nextDate.getTime()) return 1;
                else return 0;
            }else{
                if(preDate.getTime() < nextDate.getTime()) return 1;
                else return 0;
            }
        });
        res.addAll(list_sort);
        res.addAll(list_leave);
        return res;
    }

    private<T> void treeToList(T tree,List<T> list){
        Map<String,Object> map=BeanUtil.beanToMap(tree);
        list.add(tree);
        List<T> children=null;
        if(map.get("children")!=null) children=(List<T>) map.get("children");
        if(children!=null)
            for(T n:children){
                treeToList(n,list);
            }
    }

    public static<T> Map<String,Object> listToTree(List<T> list, Long rootId, String idKey, String pIdKey,String sortKey){
        List<Map<String,Object>> _list=NormalUtil.beanListToMapList(list);
        if(sortKey!=null)  _list=new TreeUtil().sort(_list,sortKey,true);
        Map<String,Object> targetNode=new HashMap<>();
        List<Map<String,Object>> children=new ArrayList<>();
        for(Map<String,Object> n:_list){
            if(rootId.equals(n.get(pIdKey))) children.add(n);
            if(rootId.equals(n.get(idKey))) targetNode=n;
        }
        if(children.size()>0) targetNode.put("children",children);
        _list.remove(targetNode);
        for(Map<String,Object> n:children){
            new TreeUtil().deepFindChildren(_list,n,idKey,pIdKey);
        }
        return targetNode;
    }

    // 这里的T必须是TreeNode实体
    public static<T> T listToTree(List<T> list, Long rootId, String idKey, String pIdKey,String sortKey,Class<T> beanT){
        List<Map<String,Object>> _list=NormalUtil.beanListToMapList(list);
        if(sortKey!=null)  _list=new TreeUtil().sort(_list,sortKey,true);
        Map<String,Object> targetNode=new HashMap<>();
        List<Map<String,Object>> children=new ArrayList<>();
        for(Map<String,Object> n:_list){
            if(rootId.equals(n.get(pIdKey))) children.add(n);
            if(rootId.equals(n.get(idKey))) targetNode=n;
        }
        if(children.size()>0) targetNode.put("children",children);
        _list.remove(targetNode);
        for(Map<String,Object> n:children){
            new TreeUtil().deepFindChildren(_list,n,idKey,pIdKey);
        }
        return BeanUtil.toBean(targetNode,beanT);
    }

    public static <T>  Map<String,Object> list2Tree(List<T> list, Long rootId, String idKey, String pIdKey,String sortKey){
        List<Map<String,Object>> _list=NormalUtil.beanListToMapList(list);
        if(sortKey!=null) _list=new TreeUtil().sort(_list,sortKey,true);
        Map<String,Object> targetNode=new HashMap<>();
        for (Map<String,Object> i:_list){
            if(i.get(idKey).equals(rootId)) targetNode=i;
            List<Map<String,Object>> children=new ArrayList<>();
            for (Map<String,Object> j:_list){
                if(i.get(idKey)==j.get(pIdKey)) children.add(j);
            }
            if(children.size()>0) i.put("children",children);
        }
        return  targetNode;
    }

    public static <T>  T list2Tree(List<T> list, Long rootId, String idKey, String pIdKey,String sortKey,Class<T> beanT){
        List<Map<String,Object>> _list=NormalUtil.beanListToMapList(list);
        if(sortKey!=null) _list=new TreeUtil().sort(_list,sortKey,true);
        Map<String,Object> targetNode=new HashMap<>();
        for (Map<String,Object> i:_list){
            if(i.get(idKey).equals(rootId)) targetNode=i;
            List<Map<String,Object>> children=new ArrayList<>();
            for (Map<String,Object> j:_list){
                if(i.get(idKey)==j.get(pIdKey)) children.add(j);
            }
            if(children.size()>0) i.put("children",children);
        }
        return BeanUtil.toBean(targetNode,beanT);
    }

    public static<T> List<Map<String,Object>> treeToList(T tree){
        List<T> list=new ArrayList<>();
        new TreeUtil().treeToList(tree,list);
        List<Map<String,Object>> mapList=NormalUtil.beanListToMapList(list);
        mapList.forEach(v->v.put("children",null));
        return mapList;
    }
    
    public static<T> List<T> treeToList(T tree,Class<T> beanT){
       List<T> list=new ArrayList<>();
       new TreeUtil().treeToList(tree,list);
       List<Map<String,Object>> mapList=NormalUtil.beanListToMapList(list);
       mapList.forEach(v->v.put("children",null));
       List<T> res=new ArrayList<>();
       mapList.forEach(v->{res.add(BeanUtil.toBean(v,beanT));});
       return res;
    }

    public static<T> List<Map<String,Object>> tree2List(T tree){
        List<Map<String,Object>> res=new ArrayList<>();
        List<Map<String,Object>> current_layer=new ArrayList<>();
        List<Map<String,Object>> next_layer=new ArrayList<>();
        current_layer.add(BeanUtil.beanToMap(tree));
        while(current_layer.size()>0){
            current_layer.forEach(v->{
                res.add(v);
                Map<String,Object> i=BeanUtil.beanToMap(v);
                if(i.get("children")!=null){
                    List<T> _children=(List<T>)i.get("children");
                    List<Map<String,Object>> children=NormalUtil.beanListToMapList(_children);
                    next_layer.addAll(children);
                }
            });
            current_layer.clear();
            current_layer.addAll(next_layer);
            next_layer.clear();
        }
        res.forEach(v->{ v.put("children",null); });
        return  res;
    }

    public static<T> List<T> tree2List(T tree,Class<T> beanT){
        List<Map<String,Object>> data=new ArrayList<>();
        List<Map<String,Object>> current_layer=new ArrayList<>();
        List<Map<String,Object>> next_layer=new ArrayList<>();
        current_layer.add(BeanUtil.beanToMap(tree));
        while(current_layer.size()>0){
            current_layer.forEach(v->{
                data.add(v);
                Map<String,Object> i=BeanUtil.beanToMap(v);
                if(i.get("children")!=null){
                      // beanToMap方法并没有深度转换，children部分还是保留了原来的数据类型,因此这里强制转换会出错。所以我们只能先转beanList再转mapList
//                    List<Map<String,Object>> children=(List<Map<String,Object>>)i.get("children");
                    List<T> _children=(List<T>)i.get("children");
                    List<Map<String,Object>> children=NormalUtil.beanListToMapList(_children);
                    next_layer.addAll(children);
                }
            });
            current_layer.clear();
            current_layer.addAll(next_layer);
            next_layer.clear();
        }
        List<T> res=new ArrayList<>();
        data.forEach(v->{
            v.put("children",null);
            res.add(BeanUtil.toBean(v,beanT));
        });
        return res;
    }

}
